/*
 SimpleWifiWithSecurity for FioV3 board using RN wifi module

 This test sketch illustrates how to use pfodSecurity
 to protect the pfodDevice with a 128bit password

 In this example, output D3 will be turned on and off from the pfodApp

  (c)2014-2015 Forward Computing and Control Pty. Ltd.
 This code may be freely used for both private and commerical use.
 Provide this copyright is maintained.
 */

// this define prints out extra info to the Arduino IDE Serial Monitor
#define DEBUG

// Download library from http://www.forward.com.au/pfod/pfodParserLibraries/index.html
#include <EEPROM.h> 
#include <pfodSecurity.h>
pfodSecurity parser; // create a parser to handle the pfod messages

// give the board pins names, if you change the pin number here you will change the pin controlled
int cmd_A_pin = 3; // name the output pin for 'Pin D3 is '

// the setup routine runs once on reset:
void setup() {
  // Open serial communications and wait for port to open:
  Serial1.begin(9600);
  Serial.begin(9600);
  // allow a little time to connect the serialMonitor before running the rest of the setup.
  for (int i = 5; i > 0; i--) {
    delay(1000);
    Serial.print(F(" "));
    Serial.print(i);
  }
  Serial.println();


#ifdef DEBUG
  parser.setDebugStream(&Serial); // call this BEFORE any other parser methods
#endif

  // this next setting is the idleTimeout default is 600sec i.e. 10min
  // the protect against a hacker taking over your connection and just hanging on to it
  // not sending any msgs but not releasing it, so preventing you from re-connecting.
  //
  // set the idle timeout in mS, default is zero i.e. never times out
  //  parser.setIdleTimeout(600); // set to 10min
  // it is recommended you set an idle timeout to prevent a hacker taking over your connection and keeping it open so preventing you from reconnecting.
  //
  parser.connect(&Serial1, F("")); // start with no password to just test the connection

  //pinMode(cmd_A_pin, INPUT_PULLUP); 
  pinMode(cmd_A_pin, OUTPUT); // output for 'Pin D3 is ' is initially LOW, uncomment line above if you want it initially HIGH
 

#ifdef DEBUG
  Serial.println("Parser Initialized:");
#endif
}

// the loop routine runs over and over again forever:
void loop() {
  byte cmd = parser.parse(); // pass it to the parser
  // parser returns non-zero when a pfod command is fully parsed
  if (cmd != 0) { // have parsed a complete msg { to }
    byte* pfodFirstArg = parser.getFirstArg(); // may point to \0 if no arguments in this msg.
    long pfodLongRtn; // used for parsing long return arguments, if any
    if ('.' == cmd) {
      // pfodApp has connected and sent {.} , it is asking for the main menu
      // send back the menu designed
      sendMainMenu();

    // now handle commands returned from button/sliders
    } else if('A'==cmd) { // user moved slider -- 'Pin D3 is '
      // set output based on slider 0 == LOW, 1 == HIGH
      parser.parseLong(pfodFirstArg,&pfodLongRtn); // parse first arg as a long
      digitalWrite(cmd_A_pin,pfodLongRtn); // set output
      sendMainMenuUpdate(); // always send back a pfod msg otherwise pfodApp will disconnect.

    } else if ('!' == cmd) {
      // CloseConnection command
      closeConnection(parser.getPfodAppStream());
    } else {
      // unknown command
      parser.print(F("{}")); // always send back a pfod msg otherwise pfodApp will disconnect.
    }
  }
  //  <<<<<<<<<<<  Your other loop() code goes here 
  
}

/*
 * Need to be able to close the connection from the pfodDevice end
 * if an invalid hash is received or the idle timer times out
 *
 * This code forces the RN wifi Xbee module to drop the connection.
 *
 * @param io -- the stream that talks to the pfodApp (via the wifi)
 *  get this from parser.getPfodAppStream()
 */
void closeConnection(Stream *io) {
  // code what ever is needed to force the link to disconnect
  // typically get into cmd mode and either reboot or close the link
  // for RN wifi Xbee module need to wait >250mS send $$$ and then wait >250mS
  // then send close and exit
  // should get EXIT back
  char EXIT[6] = {'E', 'X', 'I', 'T', 13, 10};
  boolean foundExit = false;
  while (!foundExit) {
    delay(300);
    io->write('$');
    io->write('$');
    io->write('$');
    delay(300);
    io->print("close\r");
    delay(300);
    io->print("exit\r");
    // wait for EXIT
    foundExit = io->find(EXIT, 6);
  };

}

void sendMainMenu() {
  parser.print(F("{."));  // start a Menu screen pfod message
  send_menuContents(); // send the menu contents
  parser.print(F("}"));  // close pfod message
}

void sendMainMenuUpdate() {
  parser.print(F("{:"));  // start an Update Menu pfod message
  send_menuContents(); // send the menu contents
  parser.print(F("}"));  // close pfod message
}

// modify this method if you need to update the menu to reflect state changes
void send_menuContents() {
  // send menu prompt
  parser.print(F("<w><+5><b>D3 Control using FioV3 + RN Wifi with Security"));
  // send menu items
  parser.print(F("|A~<+4><b>Pin D3 is\n`"));
  parser.print(digitalRead(cmd_A_pin)); // read current output state 0 Low or 1 High
  parser.print(F("~~Low\\High")); // Note the \\ inside the "'s to send \ 
  // ============ end of menu item ===========
}

